package com.gitee.melin.bee.util;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.text.StringSubstitutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DateTimeParamsUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(DateTimeParamsUtils.class);

    public static String convertParam(String expr, Instant scheduleTime) {
        expr = StringUtils.trim(expr);
        String dtExpr = null;
        if (StringUtils.startsWith(expr, "$[") || StringUtils.endsWith(expr, "]")) {
            dtExpr = StringUtils.substringBetween(expr, "$[", "]");
        }

        if (dtExpr == null) {
            return expr;
        }

        int operatorIndex = Math.max(StringUtils.lastIndexOf(dtExpr, "+"), StringUtils.lastIndexOf(dtExpr, "-"));
        if (operatorIndex >= dtExpr.length()) {
            throw new IllegalArgumentException("表达式格式不正确: " + dtExpr);
        }

        String operator = StringUtils.substring(dtExpr, operatorIndex);
        char unit = 0;
        int incrNum = -1;
        if (StringUtils.isNotBlank(operator)) {
            unit = operator.charAt(operator.length() - 1);
            String incrNumStr = StringUtils.substring(operator, 1, operator.length() - 1);
            incrNumStr = StringUtils.trim(incrNumStr);
            if (NumberUtils.isDigits(incrNumStr)) {
                incrNum = Integer.parseInt(incrNumStr);
            }
        }

        Map<String, Object> textParameters = new HashMap<>();
        StringSubstitutor substitutor = new StringSubstitutor(textParameters, "$[", "]");
        if (incrNum > 0) {
            boolean add = dtExpr.charAt(operatorIndex) == '+';
            String format = dtExpr.substring(0, operatorIndex);
            format = StringUtils.trim(format);

            if (unit == 'y' || unit == 'Y') {
                LocalDateTime ldt = LocalDateTime.ofInstant(scheduleTime, ZoneOffset.UTC);
                if (add) {
                    ldt = ldt.plusYears(incrNum);
                } else {
                    ldt = ldt.plusYears(incrNum);
                }
                scheduleTime = ldt.toInstant(ZoneOffset.UTC);
            } else if (unit == 'M') {
                LocalDateTime ldt = LocalDateTime.ofInstant(scheduleTime, ZoneOffset.UTC);
                if (add) {
                    ldt = ldt.plusMonths(incrNum);
                } else {
                    ldt = ldt.minusMonths(incrNum);
                }
                scheduleTime = ldt.toInstant(ZoneOffset.UTC);
            } else if (unit == 'd' || unit == 'D') {
                if (add) {
                    scheduleTime = scheduleTime.plus(incrNum, ChronoUnit.DAYS);
                } else {
                    scheduleTime = scheduleTime.minus(incrNum, ChronoUnit.DAYS);
                }
            } else if (unit == 'h' || unit == 'H') {
                if (add) {
                    scheduleTime = scheduleTime.plus(incrNum, ChronoUnit.HOURS);
                } else {
                    scheduleTime = scheduleTime.minus(incrNum, ChronoUnit.HOURS);
                }
            } else if (unit == 'm') {
                if (add) {
                    scheduleTime = scheduleTime.plus(incrNum, ChronoUnit.MINUTES);
                } else {
                    scheduleTime = scheduleTime.minus(incrNum, ChronoUnit.MINUTES);
                }
            } else if (unit == 'W' || unit == 'w') {
                LocalDateTime ldt = LocalDateTime.ofInstant(scheduleTime, ZoneOffset.UTC);
                if (add) {
                    ldt = ldt.plusWeeks(incrNum);
                } else {
                    ldt = ldt.minusWeeks(incrNum);
                }
                scheduleTime = ldt.toInstant(ZoneOffset.UTC);
            } else {
                throw new IllegalArgumentException("表达式格式不正确: " + expr);
            }

            String value = DateUtils.formatDateTime(scheduleTime, format);
            textParameters.put(dtExpr, value);
        } else {
            String value = DateUtils.formatDateTime(scheduleTime, dtExpr);
            textParameters.put(dtExpr, value);
        }

        return substitutor.replace(expr);
    }
}
